package lstore

import (
	_ "bytes"
	_ "encoding/binary"
	_ "fmt"
	_ "localstore/blob"
	"log"
	_ "sync"
	_ "crypto/md5"
)

const NumSstPerPg = 8
const NumDataBlob = 2

//The size of PgRoot must be 4096
type PgMeta struct {
	Md5sum     [16]byte
	Version    int64
	Magic      [8]byte		//'pgmeta  '
	UUID       [16]byte
	PoolId     uint16
	PgId       uint16
	Slot       int32		//the bit in bitmap
	RaftLogId  int16
	RaftMetaId int16

	DataBlobId [NumDataBlob]int64
	DataBlobSz [NumDataBlob]int64

	TmpBlobId  int64
	SstBlobId  [NumSstPerPg]int64
	DelLog     int64
	Rsv        [3920]byte
}


type Pg struct {
	repIdx int //which replica of PgMeta is used
	meta   *PgMeta
}

func (o *Osd) allocPgSlot () (slot int, ok bool) {
	for i:=0; i<NumPgBmWord; i++ {
		if ^o.meta.PgBitmap[i] == 0 {
			continue
		}
		for b:=0; b<64; b++ {
			if (o.meta.PgBitmap[b] & (1<<b)) == 0 {
				o.meta.PgBitmap[i] |= (1<<b)
				return i*64 + b, true
			}
		}
	}
	return -1, false
}

func (o *Osd) freePgSlot(slot int) (ok bool) {
	w, b := slot / 64 , slot % 64
	if w>=NumPgBmWord {
		log.Printf("slot invalid, slot=%d\n", slot)
		return false
	}
	o.meta.PgBitmap[w] &= ^(1<<b)
	return true
}

func (o *Osd) allocPg() (p *Pg) {
	slot, ok := o.allocPgSlot()
	if !ok {
		log.Printf("Cannot allocate PG Slot\n")
		return nil
	}
	meta := &PgMeta{}
	p = &Pg{}
	p.meta = meta
	meta.Version = 0
	meta.Slot = int32(slot)
	return p
}

func (o *Osd) loadPg(pg int) (p *Pg) {
	return nil
}

func (ls *LStore) pgCreate(req *LsReq) bool {
	// find osd
	o := ls.getOsd(int(req.OsdId))
	if o==nil {
		log.Printf("Cannot find the OSD, id=%d\n", req.OsdId)
		return false
	}

	// find an empty slot
	pg := o.allocPg()
	if pg == nil {
		log.Printf("Cannot allocate PG\n")
		return false
	}
	pg.meta.PoolId = req.PoolId
	pg.meta.PgId = req.PgId
	o.syncPgMeta(int(pg.meta.Slot))
	// write pg meta
	return true
}

func (ls *LStore) pgDelete(req *LsReq) {

}

func (ls *LStore) metaUpdate(req *LsReq) {

}

func (ls *LStore) metaLoad(req *LsReq) {

}

func (o *Osd) syncPgMeta(i int) bool {
	pg,ok := o.pg[i]
	if !ok {
		log.Printf("There is not a pg(i=%d) in the map\n", i)
		return false
	}
	pg.meta.Version ++
	pgmeta := []byte("pgmeta  ")
	for i:=0; i<8; i++ {
		pg.meta.Magic[i] = pgmeta[i]
	}
	off := int64(MetaSize*(1+i) + pg.repIdx * MetaSize)
	ret := o.syncMeta(off, pg.meta)
	pg.repIdx = (pg.repIdx + 1) % NumReplica
	return ret
}

